package org.bcncoding.appengine.droiding.server.fetch;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.bcncoding.appengine.droiding.server.entity.Station;
import org.bcncoding.appengine.droiding.server.entity.SystemType;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;

public class BcnFetchServlet  extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 
	 */
	private static final String BCN_URL = "http://www.bicing.com/localizaciones/localizaciones.php";
	
	private static final SystemType SYSTEM_TYPE = SystemType.jcdecaux;
	
	private static final Logger log = Logger.getLogger(BcnFetchServlet.class.getName());
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
        try {
        	log.fine("Trying to Update data for Barcelona Service...");
            URL url = new URL(BCN_URL);
            URLFetchService service = URLFetchServiceFactory.getURLFetchService();
            HTTPResponse response = service.fetch(url);
            String kml = processPage(new String(response.getContent(), "ISO-8859-1"));
            processKml(kml);
            resp.getWriter().println("Done!");
            log.fine("Data for Barcelona Service successfully updated !");
            
        } catch (MalformedURLException e) {
        	log.severe("Error retrieving data for Barcelona Service" + e.getMessage());
        } catch (IOException e) {
        	log.warning("Connection problem retrieving data for Barcelona Service" + e.getMessage());
        }
	}

	private void processKml(String kml) {
		DocumentBuilder builder = null;
		Document doc = null;
		try {
			builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			doc = builder.parse(new ByteArrayInputStream(kml.getBytes()));
			logKml(doc);			
			XPath xpath = XPathFactory.newInstance().newXPath();
			String expression = "/kml/Document";
			NodeList placemarks = (NodeList) xpath.evaluate(expression, doc, XPathConstants.NODE);
			for (int i = 0; i < placemarks.getLength(); i++) {
				if (!"Placemark".equals(placemarks.item(i).getNodeName()))
					continue;
				NodeList elements = placemarks.item(i).getChildNodes();
				String station_description = null;
				String coordinates = null;
				for (int j = 0; j < elements.getLength(); j++) {
					Node elem = elements.item(j);
					log.finest("element: " + elem.getNodeName());
					if ("description".equals(elem.getNodeName())) {
						station_description = elem.getTextContent();
					}
					if ("Point".equals(elem.getNodeName())) {
						Node coords = elem.getFirstChild();
						coordinates = coords.getTextContent();
					}					
				}
				if (station_description != null && coordinates != null)
					processStation(station_description, coordinates);
			}
		} catch (ParserConfigurationException e) {
			log.severe("Error parsing data for Barcelona Service" + e.getMessage());
		} catch (SAXException e) {
			log.severe("Error parsing data for Barcelona Service" + e.getMessage());
		} catch (IOException e) {
			log.severe("Error parsing data for Barcelona Service" + e.getMessage());
		} catch (XPathExpressionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}

	private void processStation(String station_description, String coordinates) {
		String first_piece = "<div style=\"margin:10px\"><div style=\"font:bold 11px verdana;color:#cf152c;margin-bottom:10px\">";
		String second_piece = "<div style=\"margin-left:5px;float:left;font:bold 11px verdana;color:green\">";
		int start_addr = station_description.indexOf(first_piece) + first_piece.length();
		int end_addr = station_description.indexOf("</div>");
		String address = station_description.substring(start_addr, end_addr).toUpperCase();
		String remaining = station_description.substring(end_addr + 6);
		int start_ava = remaining.indexOf(second_piece) + second_piece.length();
		int end_ava = remaining.indexOf("<br />", start_ava);
		String bikes_availability = remaining.substring(start_ava, end_ava);
		remaining = remaining.substring(end_ava + "<br />".length());
		String slot_availability = remaining.substring(0, remaining.indexOf("<br />"));
		Station station = new Station();
		station.setLastUpdate(new java.util.Date());
		station.setLocation(address);
		Double latitude = Double.parseDouble(coordinates.split(",")[0]);
		Double longitude = Double.parseDouble(coordinates.split(",")[1]);
		station.setLatitude(latitude);
		station.setLongitude(longitude);
		
		// PersistenceManagerFactory pmf = PMF.get();
		// TODO:
		// Find the stations if exists.
		// If exists retrieve station data to update.
		// If don't exists create new station data instance and persist.
		// May be add a date field to station to mark discovery date.
		
		log.fine("addr: [" + address + "] bikes: [" + bikes_availability + "] slots: [" + slot_availability + "] - coords: " + coordinates);
		
	}

	private String processPage(String page) {
		int start = page.indexOf("<kml xmlns=\"http://earth.google.es/kml/2.0\">");
		int end = page.indexOf("</kml>");
		end += 6;
		String kml = page.substring(start, end);
		return kml;
	}
	private void logKml(Document doc) {
        TransformerFactory tfactory = TransformerFactory.newInstance();
        Transformer serializer = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            serializer = tfactory.newTransformer();
            serializer.setOutputProperty(OutputKeys.INDENT, "yes");
            serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            serializer.transform(new DOMSource(doc), new StreamResult(bos));
            log.fine(bos.toString());
        } catch (TransformerException e) {
            log.warning("Cannot log kml !" + e.getMessage());
        }
	}
}
